#-*- coding: utf-8 -*-
import requests
import json
import sys
import time
import json
import os
import logging
from mlogging import RotatingFileHandler_MP, TimedRotatingFileHandler_MP
from concurrent.futures import ProcessPoolExecutor, as_completed
from multiprocessing import Manager
import uuid
import traceback
import base64
import argparse  #命令行解析工具
import hashlib
from urllib import urlencode

#新环境执行
#pip install mlogging==0.1
#pip install futures
#pip install requests


privat_H2_url = 'http://127.0.0.1:8801/TTSService/onTTS'  #  树勇 h2 service

reload(sys)
sys.setdefaultencoding('utf-8')

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--file', type=str, help='test case file')
parser.add_argument('-c', '--count', type=int, help='run count')
parser.add_argument('-p', '--process', type=int, help='process num')
parser.add_argument('-g', '--gateway', type=int, help='isNeuhub gateway')
parser.add_argument('-t', '--time', type=int, help='time dely at post')
parser.add_argument('-s', '--save', type=str, help='save file', default="")
args = parser.parse_args()
#print(args)
#parser.print_usage()
parser.print_help()

argsFile = args.file
argsCount = args.count
argsProcess = args.process
argsGateWay = args.gateway
argsTime = args.time
argsSave = args.save

print('Note: TTSPress.py  in python2.7 [source activate python2.7] ...')
print('file=%s' % argsFile)
print('count=%d' % argsCount)
print('process=%d' % argsProcess)
print('gateWay=%d' % argsGateWay)
print('time=%d' % argsTime)
print('save file=%s' % argsSave)


class HttpClient:

    def __init__(self, url):
        self.url = url
        self.ServiceParam = {
            'platform': 'Linux',
            'version': '0.0.0.1',
            'parameters': {
                'tte': '1',  #1:UTF-8 (目前仅支持UTF-8格式)
                'tim': '0',  # // 0：女声 1：男声
                'aue': '1',  #音频格式，0-wav，1-pcm，2-opus，3-mp3
                'tt': '0',  #// 文本格式,  0：文本 1：SSML
                'sp': '1.0',  #// 语速 [0.5, 2.0] wav和pcm支持4k到24k的采样率
                'sr': '16000',  #  // 采样率 opus支持8k 12k 16k 和24k的采样率
                'vol': '2.0'  # // 音量[0.1, 10.0]
            }
        }

        self.headers = {
            'Service-Type': 'synthesis',
            'Application-Id': 'd1bd6e9f-8dbf-4ea6-b92f-75dfa263304c',  # test
            'Request-Id': str(uuid.uuid1()),
            'Sequence-Id': str(1),
            'Protocol': str(1),
            'Net-State': str(2),
            'Applicator': str(0),
            'Host': 'aiapi.jd.com',  # neuhub的服务器
            'Property': json.dumps(self.ServiceParam)
        }

    def createURL(self):
        appkey = 'b148a7f7cc27a4f336e75c83a3ada768'
        sectetkey = 'c92d4ebd0d21a198af18bc53d7524eda'

        logging.info('in=1')
        m = hashlib.md5()
        nowTime = int(time.time() * 1000)
        before = sectetkey + str(nowTime)
        m.update(before.encode('utf8'))

        params = {'appkey': appkey, 'timestamp': nowTime, 'sign': m.hexdigest()}

        if argsGateWay > 0:  #走neuhub 网关
            url = '?'.join([neuhub_H2_url, urlencode(params)])
        else:
            url = privat_H2_url

        logging.info('srvURL=%s' % url)
        return url

    def save(self, data, index):
        global fp
        if index == 1:
            fp = open(argsSave, 'w+')
        else:
            fp = open(argsSave, 'a+')

        fp.write(data)
        fp.close()

    def post(self, txt):
        seq = 1
        buf = bytearray()
        ret = ''
        result = {}
        self.headers['Request-Id'] = str(uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org'))
        while True:
            try:
                self.headers['Sequence-Id'] = str(seq)
                if argsTime > 0:
                    time.sleep(argsTime)  #延时时间

                logging.info('post:reqID=%s, seqID=%d, txt=%s',   self.headers['Request-Id'], seq, txt)
                startTime = time.time()
                r = requests.post(privat_H2_url,  headers=self.headers, data=txt.encode('utf-8') if seq == 1 else '', timeout=30)
                #logging.info("resp=%s",r)
                endTime = time.time()
                if r.status_code == 200:
                    result = json.loads(r.content)
                    logging.info("result=%s",result)
                    if argsGateWay > 0 and result[ 'code'] != '10000':  # NeuHub response
                        ret = 'ERROR:getway code error! code:%s' % ( result['code'])
                        logging.error(ret)
                        break
                    result = result['result'] if argsGateWay > 0 else result  # TTS Service Reponse
                    status = result['status']
                    retReqID = result['request_id']
                    retSeqID = result['index']
                    delay = round(endTime - startTime, 4)
                    
                    #logging.info("status=%s, req=%s, seq=%s"% (status, retReqID, retSeqID))

                    if status == 0:
                        #audioData = ''
                        #if result['audio'] == '0':
                        #    audioData = ''
                        #else:
                        #    audioData = base64.decodestring(result['audio'])
                        #retProgress = result['progress']
                        #audioLen = len(result['audio'])
                        #if audioLen > 0:
                        #    self.save(audioData, seq)
                        #ret = 'SUCCEED[%d]:req=%s, seq=%s, progress=%s, delay=%4lf, audioLen=%d' % (status, retReqID, retSeqID, retProgress, delay, audioLen)
                        #logging.info(ret)
                        if retSeqID < 0:
                            logging.info("retSeqID=%d, break", retSeqID)
                            break
                        seq += 1
                    else:
                        ret = 'ERROR[%d]:req=%s, seq=%s, text:%s' % (
                            status, retReqID, retSeqID, text)
                        logging.error(ret)
                        break
                else:
                    ret = 'ERROR:code:%d' % r.status_code
                    logging.error(ret)
                    return
            except Exception as e:
                logging.error(traceback.print_exec())
                return


def logInit(loglevel, log_file, backup_count=0, consoleshow=False):
    if not os.path.exists(log_file):
        dir_path, file_name = os.path.split(log_file)
        if not os.path.isdir(dir_path):
            try:
                os.makedirs(dir_path)
            except Exception as e:
                pass
    fileTimeHandler = TimedRotatingFileHandler_MP(log_file, "D", 1,  backup_count)
    formatter = logging.Formatter(
        '[%(levelname)s] [PID:%(process)d] %(asctime)s %(message)s')
    fileTimeHandler.setFormatter(formatter)
    logging.getLogger('').addHandler(fileTimeHandler)
    logging.getLogger('').setLevel(loglevel)
    if consoleshow:
        console = logging.StreamHandler()
        console.setLevel(loglevel)
        console.setFormatter(formatter)
        logging.getLogger('').addHandler(console)


# 准备测试数据
def producer(queue, data):  #每个进程里有一个queueu
    logging.info('producer start')
    print("Test Start4...")
    for _ in range(1, max_workers):
        for index, text in enumerate(data):  #组合为一个索引序列
            #logging.info('producer:index=%d, txt=%s, size=%d' % (index, text, queue.qsize()))
            queue.put((index, text))

    #for index, _ in enumerate(range(1, max_workers)):
    #    queue.put((index, 'test_done'))
    logging.info('producer done')


# 测试客户端
def consumer(queue):
    count = argsCount
    #logging.info('consumer start count=%d' % count)
    httpClient = HttpClient(privat_H2_url)
    while True:
        if argsCount < 0:  #进行稳定性测试, 只是用过第一句话
            logging.info('start[<0] count=%d', count)
            index, text = queue.get()
            while True:
                if not text.strip():
                    logging.info('txt null')
                    continue

                if text == 'test_done':
                    logging.info('test done, continue')
                    continue
                httpClient.post(text)
            logging.info('test1 end')
        elif argsCount > 0:  #指定次数的测试, 只使用第一句话
            logging.info('start[>0] count=%d', count)
            while count > 0:
                index, text = queue.get()
                #logging.info('count=%d, index=%d, txt=%s'%(count, index, text))
                if not text.strip():
                    logging.info('txt null')
                    continue

                if text == 'test_done':
                    logging.info('test done, exit')
                    os._exit();
                httpClient.post(text)
            count = count - 1
            logging.info('test2 end')
        else:    #执行一次文本， 在外部虚幻出
            logging.info('not suppert, count=%d', count)
            #index, text = queue.get()
            #if not text.strip():
            #    logging.info('txt null')
            #    continue

            #if text == 'test_done':
            #    logging.info('consumer done')
            #    break
            #httpClient.post(text)
            #使用文本中的所有数据
            #logging.info('test3 end')

        logging.info('consumer end')
        os._exit();


if __name__ == '__main__':
    print("Test Start...")
    logInit(logging.INFO, 'test.log', 0, True)
    max_workers = argsProcess + 1

    #创建多进程
    manager = Manager()
    queue = manager.Queue()

    data = [text.strip() for text in open(argsFile, 'r')]

    with ProcessPoolExecutor(max_workers=max_workers) as executor:
        for worker in range(0, max_workers):
            if worker == 0:
                print("Test Start3...")
                executor.submit(producer, queue, data)
            else:
                executor.submit(consumer, queue)
